let http = require('lib.http'),
    xpath = require('xpath'),
    dom = require('xmldom').DOMParser,
    select = xpath.useNamespaces({
        "oai": "http://www.openarchives.org/OAI/2.0/",
        'oai_dc': 'http://www.openarchives.org/OAI/2.0/oai_dc/',
        'dc': 'http://purl.org/dc/elements/1.1/',
        'oaiidentifier': 'http://www.openarchives.org/OAI/2.0/oai-identifier'
    });

module.exports = {
    identify: function(baseUrl, proxy) {
        return http.get(baseUrl, { verb: "Identify" }, proxy)
            .then(response => {
                return Promise.resolve(response.data)
            })
            .catch(err => {
                return Promise.reject(err);
            });
    },

    identify2json: function(xml) {
        return new Promise((resolve, reject) => {
            try {
                var doc = new dom().parseFromString(xml)
                if (doc.getElementsByTagName('OAI-PMH').length > 0) {
                    let data = {
                        request: select('string(/oai:OAI-PMH/oai:request)', doc),
                        verb: select('string(/oai:OAI-PMH/oai:request/@verb)', doc),
                        responseDate: select('string(/oai:OAI-PMH/oai:responseDate)', doc),
                        Identify: {
                            repositoryName: select('string(/oai:OAI-PMH/oai:Identify/oai:repositoryName)', doc),
                            baseURL: select('string(/oai:OAI-PMH/oai:Identify/oai:baseURL)', doc),
                            protocolVersion: select('string(/oai:OAI-PMH/oai:Identify/oai:protocolVersion)', doc),
                            adminEmail: select('string(/oai:OAI-PMH/oai:Identify/oai:adminEmail)', doc),
                            earliestDatestamp: select('string(/oai:OAI-PMH/oai:Identify/oai:earliestDatestamp)', doc),
                            deletedRecord: select('string(/oai:OAI-PMH/oai:Identify/oai:deletedRecord)', doc),
                            granularity: select('string(/oai:OAI-PMH/oai:Identify/oai:granularity)', doc),
                            description: {
                                'oai-identifier': {
                                    scheme: select('string(/oai:OAI-PMH/oai:Identify/oai:description/oaiidentifier:oai-identifier/oaiidentifier:scheme)', doc),
                                    repositoryIdentifier: select('string(/oai:OAI-PMH/oai:Identify/oai:description/oaiidentifier:oai-identifier/oaiidentifier:repositoryIdentifier)', doc),
                                    delimiter: select('string(/oai:OAI-PMH/oai:Identify/oai:description/oaiidentifier:oai-identifier/oaiidentifier:delimiter)', doc),
                                    sampleIdentifier: select('string(/oai:OAI-PMH/oai:Identify/oai:description/oaiidentifier:oai-identifier/oaiidentifier:sampleIdentifier)', doc),
                                }
                            }
                        },
                        // xml: response.data
                    }
                    resolve(data)
                } else {
                    reject(xml);
                }

            } catch (err) {
                reject(err);
            }
        });
    },


    listSets: function(baseUrl, resumptionToken, proxy) {
        return http.get(baseUrl, {
                verb: 'ListSets',
                resumptionToken: resumptionToken
            }, proxy)
            .then(response => { return Promise.resolve(response.data) })
            .catch(err => Promise.reject(err));
    },

    sets2json: function(xml) {
        return new Promise((resolve, reject) => {
            let doc = new dom().parseFromString(xml)
            if (doc.getElementsByTagName('OAI-PMH').length > 0) {
                let result = {
                    request: select('string(/oai:OAI-PMH/oai:request)', doc),
                    verb: select('string(/oai:OAI-PMH/oai:request/@verb)', doc),
                    responseDate: select('string(/oai:OAI-PMH/oai:responseDate)', doc),
                    resumptionToken: {
                        token: (select('string(/oai:OAI-PMH/oai:ListSets/oai:resumptionToken)', doc)).trim(),
                        expirationDate: select('string(/oai:OAI-PMH/oai:ListSets/oai:resumptionToken/@expirationDate)', doc),
                        completeListSize: select('string(/oai:OAI-PMH/oai:ListSets/oai:resumptionToken/@completeListSize)', doc),
                        cursor: select('string(/oai:OAI-PMH/oai:ListSets/oai:resumptionToken/@cursor)', doc),
                    },
                    ListSets: [] // xml: response.data
                }



                select('/oai:OAI-PMH/oai:ListSets/oai:set', doc).forEach(set => {
                    result.ListSets.push({
                        // set: set.tagName,
                        setSpec: select('string(oai:setSpec)', set),
                        setName: select('string(oai:setName)', set),
                        setDescription: select('string(oai:setName)', set)
                    });

                });
                // console.log(success);
                resolve(result);
            } else {
                reject(xml);
            }
        })
    },

    listmetadataformats: function(baseUrl, proxy) {
        return http.get(baseUrl, { verb: "ListMetadataFormats" }, proxy)
            .then(response => {
                return Promise.resolve(response.data)
            })
            .catch(err => {
                return Promise.reject(err);
            });
    },

    metadataformats2json: function(xml) {
        console.log(xml);

        return new Promise((resolve, reject) => {
            try {
                let doc = new dom().parseFromString(xml);
                let result = {
                    request: select('string(/oai:OAI-PMH/oai:request)', doc).trim(),
                    verb: select('string(/oai:OAI-PMH/oai:request/@verb)', doc),
                    responseDate: select('string(/oai:OAI-PMH/oai:responseDate)', doc),
                    ListMetadataFormats: []
                }
                resolve(result);
            } catch {
                err => {
                    reject(err);
                }
            }
        });
    },


    listRecords: function(baseUrl, params, proxy) {
        params.verb = `ListRecords`;
        return http.get(baseUrl, params, proxy)
            .then(response => { return Promise.resolve(response.data) })
            .catch(err => { return Promise.reject(err) })
    },

    records2json: function(xml) {
        return new Promise((resolve, reject) => {
            try {
                let doc = new dom().parseFromString(xml);
                let result = {
                    request: select('string(/oai:OAI-PMH/oai:request)', doc).trim(),
                    verb: select('string(/oai:OAI-PMH/oai:request/@verb)', doc),
                    set: select('string(/oai:OAI-PMH/oai:request/@set)', doc),
                    metadataPrefix: select('string(/oai:OAI-PMH/oai:request/@metadataPrefix)', doc),
                    responseDate: select('string(/oai:OAI-PMH/oai:responseDate)', doc),
                    resumptionToken: {
                        token: select('string(/oai:OAI-PMH/oai:ListRecords/oai:resumptionToken)', doc).trim(),
                        expirationDate: select('string(/oai:OAI-PMH/oai:ListRecords/oai:resumptionToken/@expirationDate)', doc).trim(),
                        // completeListSize: parseInt(select('string(/oai:OAI-PMH/oai:ListRecords/oai:resumptionToken/@completeListSize)', doc)),
                        cursor: select('string(/oai:OAI-PMH/oai:ListRecords/oai:resumptionToken/@cursor)', doc).trim(),
                    },
                    ListRecords: [] // xml: response.data
                }

                let completeListSize = parseInt(select('string(/oai:OAI-PMH/oai:ListRecords/oai:resumptionToken/@completeListSize)', doc));
                if (completeListSize) { result.resumptionToken.completeListSize = completeListSize }


                // if (!result.request) return Promise.reject({ error: "unknow response", response });
                if (!result.request) throw ({ error: "unknow response", xml })

                // let identifierProfix = task.repository.repository;
                select('/oai:OAI-PMH/oai:ListRecords/oai:record', doc).forEach(item => {
                    // 转换 record header
                    let record = {
                            // set: set.tagName
                            header: {
                                identifier: select('string(oai:header/oai:identifier)', item),
                                datestamp: select('string(oai:header/oai:datestamp)', item),
                                status: select('string(oai:header/@status)', item),
                                setSpec: [],
                            },
                        }
                        // 转换setSpec
                    select('oai:header/oai:setSpec', item).forEach(item => {
                        record.header.setSpec.push(item.textContent)
                    });
                    // 转换metadata
                    if (item.getElementsByTagName('oai_dc:dc').length > 0) {
                        //元数据格式是oai_dc
                        record.JMETA = oai_dc2JMETA(item.getElementsByTagName('oai_dc:dc')[0]);
                    }
                    result.ListRecords.push(record);
                });
                resolve(result);
            } catch (err) {
                console.log(err);
                reject({
                    examineMessageString: "结构异常"
                });
            }
        })

        function oai_dc2JMETA(item) {
            let JMETA = { schema: 'JMETA_DC' };

            function t(path) {
                let a = [];
                select(path, item).forEach(item => {
                    let j = { text: item.textContent };
                    lang = item.attributes.getNamedItem('xml:lang');
                    if (lang) { j.lang = lang.value; }
                    a.push(j)
                })
                if (a.length > 0) return a
                else return undefined;
            }

            let title = t('dc:title');
            if (title) JMETA.title = title;
            let creator = t('dc:creator');
            if (creator) JMETA.creator = creator;
            let subject = t('dc:subject');
            if (subject) JMETA.subject = subject;
            let description = t('dc:description');
            if (description) JMETA.description = description;
            let publisher = t('dc:publisher');
            if (publisher) JMETA.publisher = publisher;
            let contributor = t('dc:contributor');
            if (contributor) JMETA.contributor = contributor;
            let date = t('dc:date');
            if (date) JMETA.date = date;
            let type = t('dc:type');
            if (type) JMETA.type = type;
            let format = t('dc:format');
            if (format) JMETA.format = format;
            let identifier = t('dc:identifier');
            if (identifier) JMETA.identifier = identifier;
            let language = t('dc:language');
            if (language) JMETA.language = language;
            let source = t('dc:source');
            if (source) JMETA.source = source;
            let relation = t('dc:relation');
            if (relation) JMETA.relation = relation;
            let coverage = t('dc:coverage');
            if (coverage) JMETA.coverage = coverage;
            let rights = t('dc:rights');
            if (rights) JMETA.rights = rights;
            // console.log(JMETA)
            return JMETA
        }
    },
}